#include "ftpserver.h"
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <signal.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pthread.h>
#include <time.h>

#define BUFSIZE 1024

#ifndef DT_DIR
#define DT_DIR 4
#endif
#ifndef DT_REG
#define DT_REG 8
#endif

void *log_handle(void *arg) {
    pthread_detach(pthread_self());
    CLI_MES *mes = (CLI_MES *)arg;
    CLI_INFO *pcli = mes->pcli;
    int cmd_no = mes->cmd_no;
    int result = mes->result;
    char *filename = mes->filename;
    char t[256] = {0};
    time_t curr_time;
    time(&curr_time);
    ctime_r(&curr_time, t);
    if (cmd_no == 100) {
        fprintf(pcli->fp, "%s", t);
        fprintf(pcli->fp, "%s:%d online\n", pcli->ip, pcli->port);
    }
    else if (cmd_no == FTP_CMD_BYE) {
        fprintf(pcli->fp, "%s", t);
        fprintf(pcli->fp, "%s:%d offline\n", pcli->ip, pcli->port);
    } else if (cmd_no == FTP_CMD_GET) {
        fprintf(pcli->fp, "%s", t);
        fprintf(pcli->fp, "%s:%d get %s %s\n", pcli->ip, pcli->port, filename, (result == 1 ? "success" : "failed"));
    } else if (cmd_no == FTP_CMD_LS) { 
        fprintf(pcli->fp, "%s", t); 
        fprintf(pcli->fp, "%s:%d ls\n", pcli->ip, pcli->port);
    } else if (cmd_no == FTP_CMD_PUT) {
        fprintf(pcli->fp, "%s", t);
        fprintf(pcli->fp, "%s:%d put %s %s\n", pcli->ip, pcli->port, filename, (result == 1 ? "success" : "failed"));
    } else if (cmd_no == FTP_CMD_CD) {
        fprintf(pcli->fp, "%s", t);
        fprintf(pcli->fp, "%s:%d cd %s %s\n", pcli->ip, pcli->port, filename, (result == 1 ? "success" : "failed"));
    } else if (cmd_no == FTP_CMD_GETDIR) {
        fprintf(pcli->fp, "%s", t);
        fprintf(pcli->fp, "%s:%d getdir %s %s\n", pcli->ip, pcli->port, filename, (result == 1 ? "success" : "failed"));
    } else if (cmd_no == FTP_CMD_PUTDIR) {
        fprintf(pcli->fp, "%s", t);
        fprintf(pcli->fp, "%s:%d putdir %s %s\n", pcli->ip, pcli->port, filename, (result == 1 ? "success" : "failed"));
    }
    fflush(pcli->fp);
    free(arg);
}

void sendFile(int confd, const char *filename) {
    int fd = open(filename, O_RDONLY);
    if (-1 == fd) {
        char errormsg[BUFSIZE] = {0};
        snprintf(errormsg, BUFSIZE, "get file failed:%s", strerror(errno));
        send(confd, errormsg, strlen(errormsg), 0);
    } else {
        while (1) {
            char buf[1024] = {0};
            int r = read(fd, buf, sizeof(buf));
            if (r <= 0) {
                break;
            }
            write(confd, buf, r);
        }
    }
}

void handle_read_error(CLI_INFO *pcli) {
    close(pcli->fd);
    printf("disconnect client IP:%s, client port:%d\n", pcli->ip, pcli->port);
}

int init_tcpserver(const char *ip, short port) {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd) {
        perror("create scocket failed");
        exit(-1);
    }
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(port);
    // saddr.sin_addr.s_addr = inet_addr(ip);
    saddr.sin_addr.s_addr = INADDR_ANY;
    if (-1 == bind(sockfd, (struct sockaddr *)&saddr, sizeof(struct sockaddr))) {
        perror("bind failed");
        exit(-1);
    }
    if (-1 == listen(sockfd, 5)) {
        perror("listen failed");
        exit(-1);
    }
    printf("init socket success!\n");
    return sockfd;
}

void my_sighandler(int sig) {
    switch(sig) {
        case SIGCHLD:
            wait(NULL);
            break;
        default:
            break;
    }
}

void handle_connection(CLI_INFO *pcli) {
#ifdef DEBUG
    printf("handle client IP:%s, client port:%d\n", pcli->ip, pcli->port);
#endif
    while (1) {
        unsigned char cmd[1024] = {0};
        int r;
        unsigned char ch;
        do {
            r = read(pcli->fd, &ch, 1);
            if (r <= 0) {
                handle_read_error(pcli);
                exit(0);   /*客户端主动断开连接*/
            }
        } while (ch != 0xc0);
        while (ch == 0xc0) {
            r = read(pcli->fd, &ch, 1);
            if (r <= 0) {
                handle_read_error(pcli);
                exit(0);
            }
        }
        int i = 0;
        while (ch != 0xc0) {
            cmd[i++] = ch;
            r = read(pcli->fd, &ch, 1);
            if (r <= 0) {
                handle_read_error(pcli);
                exit(0);
            }
        }
        int pkg_len = cmd[0] | (cmd[1] << 8) | (cmd[2] << 16) | (cmd[3] << 24);
        if (i != pkg_len) { /*实际读取到的字节数和理论上的字节数不一致*/
            printf("pkg_len = %d, read len = %d\n", pkg_len, i);
            continue;
        }
        int cmd_no = cmd[4] | (cmd[5] << 8) | (cmd[6] << 16) | (cmd[7] << 24);
        CLI_MES *mes = (CLI_MES *)malloc(sizeof(CLI_MES));
        mes->pcli = pcli;
        if (cmd_no == FTP_CMD_BYE) {
            pthread_t tid;
            mes->cmd_no = FTP_CMD_BYE;
            mes->result = 1;
            pthread_create(&tid, NULL, log_handle, (void *)mes);
            close(pcli->fd);
            printf("disconnect client IP:%s, client port:%d\n", pcli->ip, pcli->port);
            pthread_join(tid, NULL);
            fclose(pcli->fp);
            break;
        } else if (cmd_no == FTP_CMD_GET) {
            // 包头(1)	包长度(4)	 命令号(4)  参数长度(4)  参数内容(文件名长度)  包尾(1)
            char filename[256] = {0};
            int len = cmd[8] | (cmd[9] << 8) | (cmd[10] << 16) | (cmd[11] << 24);
            memcpy(filename, cmd + 12, len);
#ifdef DEBUG
            printf("get %s\n", filename);
#endif
            mes->cmd_no = FTP_CMD_GET;
            memset(mes->filename, 0, sizeof(mes->filename));
            strcpy(mes->filename, filename);
            mes->result = resp_get(pcli, filename);
            pthread_t tid;
            pthread_create(&tid, NULL, log_handle, (void *)mes);
        } else if (cmd_no == FTP_CMD_PUT) {
            // 包头(1)	包长度(4)	 命令号(4)  参数长度(4)  参数内容(文件名长度) 参数二内容(4):文件的大小 包尾(1)
            char filename[256] = {0};
            int len = cmd[8] | (cmd[9] << 8) | (cmd[10] << 16) | (cmd[11] << 24);
            memcpy(filename, cmd + 12, len);
            int filesize = cmd[12 + len] | (cmd[12 + len + 1] << 8) | (cmd[12 + len + 2] << 16) | (cmd[12 + len + 3] << 24);
            mes->cmd_no = FTP_CMD_PUT;
            memset(mes->filename, 0, sizeof(mes->filename));
            strcpy(mes->filename, filename);
            mes->result = resp_put(pcli, filename, filesize);
            pthread_t tid;
            pthread_create(&tid, NULL, log_handle, (void *)mes);
#ifdef DEBUG
            printf("put %s\n", filename);
#endif
        } else if (cmd_no == FTP_CMD_LS) {
#ifdef DEBUG
            printf("ls\n");
#endif
            mes->cmd_no = FTP_CMD_LS;
            pthread_t tid;
            pthread_create(&tid, NULL, log_handle, (void *)mes);
            resp_ls(pcli);
        } 
        else if (cmd_no == FTP_CMD_PWD) {
#ifdef DEBUG
            printf("pwd\n");
#endif
            resp_pwd(pcli);
        } else if (cmd_no == FTP_CMD_CD) {
            mes->cmd_no = FTP_CMD_CD;
            char dirname[256] = {0};
            int len = cmd[8] | (cmd[9] << 8) | (cmd[10] << 16) | (cmd[11] << 24);
            memcpy(dirname, cmd + 12, len);
            printf("cd %s\n", dirname);
            memset(mes->filename, 0, sizeof(mes->filename));
            strcpy(mes->filename, dirname);
            mes->result = resp_cd(pcli, dirname);
            pthread_t tid;
            pthread_create(&tid, NULL, log_handle, (void *)mes);
        } 
        else if (cmd_no == FTP_CMD_GETDIR) {
            char dirname[256] = {0};
            int len = cmd[8] | (cmd[9] << 8) | (cmd[10] << 16) | (cmd[11] << 24);
            memcpy(dirname, cmd + 12, len);
            printf("getdir %s\n", dirname);
            mes->result = resp_getdir(pcli, dirname);
            mes->cmd_no = FTP_CMD_GETDIR;
            memset(mes->filename, 0, sizeof(mes->filename));
            strcpy(mes->filename, dirname);
            pthread_t tid;
            pthread_create(&tid, NULL, log_handle, (void *)mes);
        } else if (cmd_no == FTP_CMD_PUTDIR) {
            char dirname[256] = {0};
            int len = cmd[8] | (cmd[9] << 8) | (cmd[10] << 16) | (cmd[11] << 24);
            memcpy(dirname, cmd + 12, len);
            printf("getdir %s\n", dirname);
            memset(mes->filename, 0, sizeof(mes->filename));
            strcpy(mes->filename, dirname);
            mes->cmd_no = FTP_CMD_PUTDIR;
            mes->result = resp_putdir(pcli, dirname);
            pthread_t tid;
            pthread_create(&tid, NULL, log_handle, (void *)mes);
        } else if (cmd_no == FTP_CMD_STAT) {
            char dirname[256] = {0};
            int len = cmd[8] | (cmd[9] << 8) | (cmd[10] << 16) | (cmd[11] << 24);
            memcpy(dirname, cmd + 12, len);
            printf("stat %s\n", dirname);
            resp_stat(pcli, dirname);
        }
        else {
            free(mes);
        }
    }
    free(pcli);
}

void resp_ls(CLI_INFO *pcli) {
    printf("client resquest ls %s:%d\n", pcli->ip, pcli->port);
    unsigned char filenames[4096] = {0};
    int result = 0;
    char cur_dir[256];
    DIR *dir = opendir(getcwd(cur_dir, sizeof(cur_dir)));
    if (dir == NULL) {
        result = 1;
    } else {
        struct dirent *dirp = NULL;
        int r = 0;
        while (dirp = readdir(dir)) {
            if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0) {
                continue;
            }
            r += sprintf(filenames + r, "%s\r\n", dirp->d_name);
        }
        closedir(dir);
    }
    printf("filenames:%s\nlen = %ld\n", filenames, strlen(filenames));
    char resp[8192] = {0};
    int resplen = 1 + ((result == 1) ? 4 : strlen(filenames));
    int pkg_len = 4 + 4 + 4 + resplen;
    int i = 0;
    resp[i++] = 0xc0;
    resp[i++] = 0xff & (pkg_len);
    resp[i++] = 0xff & (pkg_len >> 8);
    resp[i++] = 0xff & (pkg_len >> 16);
    resp[i++] = 0xff & (pkg_len >> 24);

    enum CMD_NO cmd_no = FTP_CMD_LS;
    resp[i++] = 0xff & (cmd_no);
    resp[i++] = 0xff & (cmd_no >> 8);
    resp[i++] = 0xff & (cmd_no >> 16);
    resp[i++] = 0xff & (cmd_no >> 24);

    resp[i++] = 0xff & (resplen);
    resp[i++] = 0xff & (resplen >> 8);
    resp[i++] = 0xff & (resplen >> 16);
    resp[i++] = 0xff & (resplen >> 24);

    resp[i++] = result;
    if (result == 1) {
        resp[i++] = 0xff & (errno);
        resp[i++] = 0xff & (errno >> 8);
        resp[i++] = 0xff & (errno >> 16);
        resp[i++] = 0xff & (errno >> 24);
    } else {
        /*将filename的最后两个字符，即回车换行去掉*/
        // filenames[strlen(filenames) - 1] = '\0';
        memcpy(resp + i, filenames, strlen(filenames));
        i += (strlen(filenames));
    }
    resp[i++] = 0xc0;
#ifdef DEBUG
    printf("pkg_len = %d\n", pkg_len);
#endif
    write(pcli->fd, resp, i);
}

bool resp_get(CLI_INFO *pcli, const char *filename) {
    bool ret = true;
    char resp[1024] = {0};
    int i = 0;
    char result = 0;
    int filesize = 0;
    // if (chdir(FTPDIR) == -1) {
    //     perror("chdir failed");
    //     ret = false;
    // }
    int fd = open(filename, O_RDONLY, 0664);
    if (-1 == fd) {
        perror("open failed");
        result = 1;
        ret = false;
    } else {
        /*获取文件的大小*/
        struct stat st;
        if (-1 == stat(filename, &st)) {
            perror("stat failed");
            result = 1;
            ret = false;
        } else {
            // 包头(1)	包长度(4)	命令号(4)	回复长度(4)   结果(1)	 回复内容(文件的长度) 包尾(1)
            if (!S_ISREG(st.st_mode)) {
                printf("%s is not regular file\n", filename);
                errno = EISDIR;
                result = 1;
                ret = false;
            }
            filesize =st.st_size;
        }
    }
#ifdef DEBUG
    printf("filesize = %d\n", filesize);
#endif
    resp[i++] = 0xc0;
    int resp_len = 1 + 4;
    int pkg_len = 4 + 4 + 4 + resp_len;
    resp[i++] = 0xff & (pkg_len);
    resp[i++] = 0xff & (pkg_len >> 8);
    resp[i++] = 0xff & (pkg_len >> 16);
    resp[i++] = 0xff & (pkg_len >> 24);

    enum CMD_NO cmd_no = FTP_CMD_GET;
    resp[i++] = 0xff & (cmd_no);
    resp[i++] = 0xff & (cmd_no >> 8);
    resp[i++] = 0xff & (cmd_no >> 16);
    resp[i++] = 0xff & (cmd_no >> 24);

    resp[i++] = 0xff & (resp_len);
    resp[i++] = 0xff & (resp_len >> 8);
    resp[i++] = 0xff & (resp_len >> 16);
    resp[i++] = 0xff & (resp_len >> 24);
    
    resp[i++] = result;

    if (result) {
        resp[i++] = 0xff & (errno);
        resp[i++] = 0xff & (errno >> 8);
        resp[i++] = 0xff & (errno >> 16);
        resp[i++] = 0xff & (errno >> 24);
    } else {
        resp[i++] = 0xff & (filesize);
        resp[i++] = 0xff & (filesize >> 8);
        resp[i++] = 0xff & (filesize >> 16);
        resp[i++] = 0xff & (filesize >> 24);
    }
    resp[i++] = 0xc0;
    write(pcli->fd, resp, i);
    /*如果获取正常，开始发送文件*/
    if (result == 0) {
        while (1) {
            char buf[1024] = {0};
            int r = read(fd, buf, sizeof(buf));
            if (r <= 0) {
                break;
            }
            write(pcli->fd, buf, r);
        }
#ifdef DEBUG
            printf("send succesfully!\n");
#endif
            printf("send %s succesfully!\n", filename);
    }
    close(fd);
    return ret;
}

bool resp_put(CLI_INFO *pcli, const char *filename, int filesize_) {
    int ret = true;
#ifdef DEBUG
    printf("filesize = %d\n", filesize_);
#endif
    /*1.接收客户端上传的文件*/
    // chdir(FTPDIR);
    int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0664);
    int result = 0;
    if (-1 == fd) {
        perror("open failed");
        result = 1;
        ret = false;
    } else {
        int cur_read = 0;
        if (filesize_ < 1024) {
            unsigned char buf[1024] = {0};
            int r =read(pcli->fd, buf, filesize_);
            write(fd, buf, r);
        }
        else {
            while (cur_read < filesize_) {
                unsigned char buf[1024] = {0};
                if (filesize_ - cur_read < 1024) {
                    int r =read(pcli->fd, buf, filesize_ - cur_read);
                    write(fd, buf, r);
                    cur_read += r;
                    break;
                }
                int r =read(pcli->fd, buf, sizeof(buf));
                if (r <= 0) {
                    break;
                }
                write(fd, buf, r);
                cur_read += r;
            }
        }
        close(fd);
    }
    /*2.发送客户端其接收文件的情况，是否接收成功*/
    // 包头(1)	包长度(4)	命令号(4)	回复长度(4)   结果(1)	 回复内容(文件的长度) 包尾(1)
    unsigned char resp[1024] = {0};
    int i = 0;
    struct stat st;
    int filesize = 0;
    if (-1 == stat(filename, &st)) {
        ret = false;
        result = 1;
    } else {   
        filesize = st.st_size;
    }
    resp[i++] = 0xc0;
    int resp_len = 1 + 4;
    int pkg_len = 4 + 4 + 4 + resp_len;
    resp[i++] = 0xff & (pkg_len);
    resp[i++] = 0xff & (pkg_len >> 8);
    resp[i++] = 0xff & (pkg_len >> 16);
    resp[i++] = 0xff & (pkg_len >> 24);

    enum CMD_NO cmd_no = FTP_CMD_PUT;
    resp[i++] = 0xff & (cmd_no);
    resp[i++] = 0xff & (cmd_no >> 8);
    resp[i++] = 0xff & (cmd_no >> 16);
    resp[i++] = 0xff & (cmd_no >> 24);

    resp[i++] = 0xff & (resp_len);
    resp[i++] = 0xff & (resp_len >> 8);
    resp[i++] = 0xff & (resp_len >> 16);
    resp[i++] = 0xff & (resp_len >> 24);
    
    resp[i++] = result;

    if (result) {
        resp[i++] = 0xff & (errno);
        resp[i++] = 0xff & (errno >> 8);
        resp[i++] = 0xff & (errno >> 16);
        resp[i++] = 0xff & (errno >> 24);
    } else {
        resp[i++] = 0xff & (filesize);
        resp[i++] = 0xff & (filesize >> 8);
        resp[i++] = 0xff & (filesize >> 16);
        resp[i++] = 0xff & (filesize >> 24);
        printf("received %s successfully\n", filename);
    }
    resp[i++] = 0xc0;
    write(pcli->fd, resp, i);
    return ret;
}

bool resp_pwd(CLI_INFO *pcli) {
    int ret = true;
    int i = 0;
    int result = 0;		/*对客户端的请求处理的结果，0表示处理成功，1表示处理失败*/
    unsigned char curr_dir[256] = {0};
    if (getcwd(curr_dir, sizeof(curr_dir)) == NULL) {
        perror("getcwd failed");
        result = 1;
    }
#ifdef DEBUG
    printf("pwd: %s\n", curr_dir);
#endif
    /*处理需要发送的数据*/
    char resp[1024] = {0};
    resp[i++] = 0xc0;
    /*回复长度，即当前目录名的长度/错误码 + 结果*/
    int resp_len = 1 + (result == 0 ? strlen(curr_dir) : 4);	
    int pkg_len = 4 + 4 + 4 + resp_len;
    int cmd_no = FTP_CMD_PWD;
    /*包长度*/
    resp[i++] = 0xff & (pkg_len);
    resp[i++] = 0xff & (pkg_len >> 8);
    resp[i++] = 0xff & (pkg_len >> 16);
    resp[i++] = 0xff & (pkg_len >> 24);
    /*命令号*/
    resp[i++] = 0xff & (cmd_no);
    resp[i++] = 0xff & (cmd_no >> 8);
    resp[i++] = 0xff & (cmd_no >> 16);
    resp[i++] = 0xff & (cmd_no >> 24);
    /*回复长度*/
    resp[i++] = 0xff & (resp_len);
    resp[i++] = 0xff & (resp_len >> 8);
    resp[i++] = 0xff & (resp_len >> 16);
    resp[i++] = 0xff & (resp_len >> 24);

    /*处理结果*/
    resp[i++] = result;
    if (result) {
        /*处理失败，发送错误码*/
        resp[i++] = 0xff & (errno);
        resp[i++] = 0xff & (errno >> 8);
        resp[i++] = 0xff & (errno >> 16);
        resp[i++] = 0xff & (errno >> 24);
    } else {
        /*处理成功，发送当前的目录名*/
        memcpy(resp + i, curr_dir, strlen(curr_dir));
        i += strlen(curr_dir);
    }
    resp[i++] = 0xc0;
    write(pcli->fd, resp, i);
    return ret;
}

bool resp_cd(CLI_INFO *pcli, const char *dirname) {
    bool ret = true;
    int result = 0;		/*对客户端的请求处理的结果，0表示处理成功，1表示处理失败*/
    unsigned char curr_dir[256] = {0};
    int i = 0;
    if (-1 == chdir(dirname)) {
        perror("chdir failed");
        ret = false;
        result = 1;
    }
    if (getcwd(curr_dir, sizeof(curr_dir)) == NULL) {
        perror("getcwd failed");
        ret = false;
        result = 1;
    }
    /*处理需要发送的数据*/
    char resp[1024] = {0};
    resp[i++] = 0xc0;
    /*回复长度，即当前目录名的长度/错误码 + 结果*/
    int resp_len = 1 + (result == 0 ? strlen(curr_dir) : 4);	
    int pkg_len = 4 + 4 + 4 + resp_len;
    int cmd_no = FTP_CMD_CD;
    /*包长度*/
    resp[i++] = 0xff & (pkg_len);
    resp[i++] = 0xff & (pkg_len >> 8);
    resp[i++] = 0xff & (pkg_len >> 16);
    resp[i++] = 0xff & (pkg_len >> 24);
    /*命令号*/
    resp[i++] = 0xff & (cmd_no);
    resp[i++] = 0xff & (cmd_no >> 8);
    resp[i++] = 0xff & (cmd_no >> 16);
    resp[i++] = 0xff & (cmd_no >> 24);
    /*回复长度*/
    resp[i++] = 0xff & (resp_len);
    resp[i++] = 0xff & (resp_len >> 8);
    resp[i++] = 0xff & (resp_len >> 16);
    resp[i++] = 0xff & (resp_len >> 24);

    /*处理结果*/
    resp[i++] = result;
    if (result) {
        /*处理失败，发送错误码*/
        resp[i++] = 0xff & (errno);
        resp[i++] = 0xff & (errno >> 8);
        resp[i++] = 0xff & (errno >> 16);
        resp[i++] = 0xff & (errno >> 24);
    } else {
        /*处理成功，发送当前的目录名*/
        memcpy(resp + i, curr_dir, strlen(curr_dir));
        i += strlen(curr_dir);
    }
    resp[i++] = 0xc0;
    write(pcli->fd, resp, i);
    return ret;
}

bool resp_getdir(CLI_INFO *pcli, const char *dirname_) {
    struct stat st;
    bool ret = true;
    int result = 0;
    int errnum = 0;
    int dirsize = 0;
    if (-1 == stat(dirname_, &st)) {
        result = 1;
        ret = false;
    } else if (S_ISDIR(st.st_mode)) {
        dirsize = st.st_size;
    } else {
        ret = false;
        result = 1;
        errnum = ENOTDIR;
    }
    // 包头(1) 	包长度(4) 	命令号(4) 	回复长度(4)	   结果(1)  回复长度(文件夹的大小/错误码) 包尾(1)
    unsigned char resp[1024] = {0};
    int i = 0;
    int resp_len = 4;
    int pkg_len = 4 + 4 + 4 + 1 + resp_len;
    resp[i++] = 0xc0;
    resp[i++] = 0xff & (pkg_len);
    resp[i++] = 0xff & (pkg_len >> 8);
    resp[i++] = 0xff & (pkg_len >> 16);
    resp[i++] = 0xff & (pkg_len >> 24);

    int cmd_no = FTP_CMD_GETDIR;
    resp[i++] = 0xff & (cmd_no);
    resp[i++] = 0xff & (cmd_no >> 8);
    resp[i++] = 0xff & (cmd_no >> 16);
    resp[i++] = 0xff & (cmd_no >> 24);

    resp[i++] = 0xff & (resp_len);
    resp[i++] = 0xff & (resp_len >> 8);
    resp[i++] = 0xff & (resp_len >> 16);
    resp[i++] = 0xff & (resp_len >> 24);
    resp[i++] = result;
    if (result) {
        int t = (errnum == 0) ? errno : errnum;
        resp[i++] = 0xff & (t);
        resp[i++] = 0xff & (t >> 8);
        resp[i++] = 0xff & (t >> 16);
        resp[i++] = 0xff & (t >> 24);
    } else {
        resp[i++] = 0xff & (dirsize);
        resp[i++] = 0xff & (dirsize >> 8);
        resp[i++] = 0xff & (dirsize >> 16);
        resp[i++] = 0xff & (dirsize >> 24);
    }
    resp[i++] = 0xc0;
    write(pcli->fd, resp, i);
    /*如果没有问题开始发送文件*/
    char curr_dir[256] = {0};
    getcwd(curr_dir, sizeof(curr_dir));
    char dirname[1024] = {0};
    realpath(dirname_, dirname);
    if (result == 0) {
        DIR *dirp = opendir(dirname);
        struct dirent *dp = NULL;
        chdir(dirname);
        int flag = 1;
        while (dp = readdir(dirp)) {
            if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
                continue;
            }
            if (dp->d_type == DT_DIR) { //4
                /*递归复制*/
                /*先发送文件夹名 + 文件类型(8)*/
                write(pcli->fd, "d", 1);
                /*为了防止客户端阻塞，文件名的长度要固定，如果不到256，就补充*/
                write(pcli->fd, dp->d_name, 256);
                resp_getdir(pcli, dp->d_name);
#ifdef DEBUG
                printf("send dir %s\n", dp->d_name);
#endif
            } else if (dp->d_type == DT_REG) { //8
                /*先发送文件名 + 文件类型*/
                write(pcli->fd, "r", 1);
                write(pcli->fd, dp->d_name, 256);
                resp_get(pcli, dp->d_name);
#ifdef DEBUG
                printf("send file %s/%s\n", dirname, dp->d_name);
                flag = 0;
#endif
            }
        }
        chdir(curr_dir);
        /*循环结束发送结束的数据包*/
        #ifdef DEBUG
        printf("send over\n");
        #endif
        write(pcli->fd, "#", 1);
        write(pcli->fd, "over", 256);
    }
    return ret;
}

/*待完善，以.开头的文件夹无法返回上级目录*/
bool resp_putdir(CLI_INFO *pcli, const char *dirname) {
    int ret = true;
    /*创建文件夹*/
    /*先接收文件*/
    char dir_name[256] = {0};
    char curr_dir[256] = {0};
    mkdir(dirname, 0777);
    getcwd(curr_dir, sizeof(curr_dir));
    chdir(dirname);
    getcwd(dir_name, sizeof(dir_name));
    char type;
    char filename[256] = {0};
    read(pcli->fd, &type, 1);
    read(pcli->fd, filename, 256);
    unsigned char fs[4];
    read(pcli->fd, fs, 4);
    int filesize = fs[0] | (fs[1] << 8) | (fs[2] << 16) | (fs[3] << 24);
    while (strncmp(filename, "over", 4) != 0) {
        chdir(dir_name);
        printf("dir_name = %s\n", dir_name);
        if (type == 'd') {
#ifdef DEBUG
            printf("get dir %s/%s\n", dir_name, filename);
#endif
            handle_connection(pcli);
        } else if (type == 'r') {
#ifdef DEBUG
            printf("get file %s/%s\n", dir_name, filename);
#endif
            handle_connection(pcli);
        }
        memset(filename, 0, sizeof(filename));
        read(pcli->fd, &type, 1);
        read(pcli->fd, filename, 256);
        unsigned char fs[4];
        read(pcli->fd, fs, 4);
        printf("file = %s\n", filename);
        chdir(curr_dir);
    }
    chdir(curr_dir);
    printf("接收完毕\n");
    /*再发送回复信息*/
    return ret;
}

bool resp_stat(CLI_INFO *pcli, const char *dirname) {
    int ret =true;
    int result = 0;
    struct stat st;
    unsigned char type = 0;
    if (-1 == stat(dirname, &st)) {
        perror("stat failed");
        result = 1;
        ret = false;
    } else {
        if (S_ISREG(st.st_mode)) {
            type = 'r';
        } else if (S_ISDIR(st.st_mode)) {
            type = 'd';
        } 
    }
    unsigned char resp[1024] = {0};
    int i = 0;
    resp[i++] = 0xc0;
    int pkg_len = 4 + 4 + 1 + 1;
    enum CMD_NO cmd_no = FTP_CMD_STAT;
    resp[i++] = 0xff & (pkg_len);
    resp[i++] = 0xff & (pkg_len >> 8);
    resp[i++] = 0xff & (pkg_len >> 16);
    resp[i++] = 0xff & (pkg_len >> 24);
    resp[i++] = 0xff & (cmd_no);
    resp[i++] = 0xff & (cmd_no >> 8);
    resp[i++] = 0xff & (cmd_no >> 16);
    resp[i++] = 0xff & (cmd_no >> 24);
    resp[i++] = result;
    resp[i++] = type;
    resp[i++] = 0xc0;
    write(pcli->fd, resp, i);
    return ret;
}